﻿using System;
using Firestarter.DB.Schema.BO;
using Firestarter.DB.Schema.Test.BO.TestUtils;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using Habanero.Base.Exceptions;
using Habanero.BO;
using NUnit.Framework;
using Rhino.Mocks;

namespace Firestarter.DB_DomainModel.Logic.Test
{
    [TestFixture]
    public class TestDBToDMReverseEngineeringController : TestBase
    {
        [Test]
// ReSharper disable InconsistentNaming
        public void Test_Construct_WhenCalledWithNullSolutionParameter_ShouldThrowException()
        {
            //---------------Set up test pack-------------------
            
            //---------------Assert Precondition----------------
            try
            {
                //---------------Execute Test ----------------------
                DMSolution solution = null;
                new DBToDMReverseEngineeringController(solution);
                Assert.Fail("Expected to throw an EXCEPTION");
            } 
            catch (Exception ex)
            {
                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("Solution is null", ex.Message);
            }

        }

        [Test]
        public void Test_Construct_WhenCalledWithValidNewSolution_ShouldConstruct()
        {
            //---------------Set up test pack-------------------
            var solution = new DMSolution();
            //---------------Assert Precondition----------------
            Assert.IsNotNull(solution);
            //---------------Execute Test ----------------------
            var controller = new DBToDMReverseEngineeringController(solution);
            //---------------Test Result -----------------------
            Assert.IsNotNull(controller);
            Assert.AreSame(solution, controller.Solution);
        }

        [Test]
        public void Test_Construct_WhenCalledWithValidEmptySolution_ShouldConstruct()
        {
            //---------------Set up test pack-------------------
            var solution = new SolutionCreator().CreateSolution();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            var controller = new DBToDMReverseEngineeringController(solution);
            //---------------Test Result -----------------------
            Assert.IsNotNull(controller);
            Assert.AreSame(solution, controller.Solution);

        }

        [Test]
        public void Test_CreateDBToDMImporterFactory_WhenCalledAndSolutionIsNotNull_ShouldReturnNewDBToDMImporterFactoryForCurrentSolution()
        {
            //---------------Set up test pack-------------------
            var solution = new SolutionCreator().CreateSolution();
            var controller = new DBToDMReverseEngineeringControllerSpy(solution);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(controller.Solution);
            Assert.IsInstanceOf<DBToDMReverseEngineeringController>(controller);

            //---------------Execute Test ----------------------
            IDBToDMImporterFactory dbtoDMImporterFactory = controller.CreateDBToDMImporterFactory();
            //---------------Test Result -----------------------
            Assert.IsNotNull(dbtoDMImporterFactory);
            Assert.AreSame(solution, ((PropertyTypeStorer)controller.PropertyTypeStorerGetter()).Solution);
        }

        [Test]
        public void Test_CreateReverseEngineeringForSolution_WhenCalledWithNullParameters_ShouldThrowException()
        {
            //---------------Set up test pack-------------------
            DBToDMReverseEngineeringController controller = CreateDBToDMReverseEngineeringControllerWithEmptySolution();
            ReverseEngineeringSettings reverseEngineeringSettings = null;
            DatabaseConnectionInfo databaseConnectionInfo = null;
            //---------------Assert Precondition----------------
            Assert.IsNull(reverseEngineeringSettings);
            Assert.IsNull(databaseConnectionInfo);

            try
            {
                controller.CreateReverseEngineeringForSolution(reverseEngineeringSettings, databaseConnectionInfo);
                //---------------Execute Test ----------------------
                Assert.Fail("Expected to throw an Exception");
            } 
            catch (Exception ex)
            {
                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("reverseEngineeringSettings is null", ex.Message);
            }
        }

        [Test]
        public void Test_CreateReverseEngineeringForSolution_WhenCalledWithValidReverseEngineeringSettingsAndNullDatabaseConnectionInfo_ShouldThrowException()
        {
            //---------------Set up test pack-------------------
            DBToDMReverseEngineeringController controller = CreateDBToDMReverseEngineeringControllerWithEmptySolution();
            ReverseEngineeringSettings reverseEngineeringSettings = new ReverseEngineeringSettings();
            DatabaseConnectionInfo databaseConnectionInfo = null;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(reverseEngineeringSettings);
            Assert.IsNull(databaseConnectionInfo);
            try
            {
                controller.CreateReverseEngineeringForSolution(reverseEngineeringSettings, databaseConnectionInfo);
                //---------------Execute Test ----------------------
                Assert.Fail("Expected to throw an Exception");
            }
            catch (Exception ex)
            {
                //---------------Test Result -----------------------
                Assert.IsInstanceOf<HabaneroDeveloperException>(ex);
                StringAssert.Contains("databaseConnectionInfo is null", ex.Message);
            }
        }


        [Test]
        public void Test_CreateReverseEngineeringForSolution_WhenCalledWithValidParameters_ShouldReturnReverseEngineeringNowAssociatedWithTheSolution()
        {
            //---------------Set up test pack-------------------
            DBToDMReverseEngineeringController controller = CreateDBToDMReverseEngineeringControllerWithEmptySolution();
            ReverseEngineeringSettings reverseEngineeringSettings = new ReverseEngineeringSettings();
            DatabaseConnectionInfo databaseConnectionInfo = new DatabaseConnectionInfo();            
            //---------------Assert Precondition----------------
            Assert.IsNotNull(reverseEngineeringSettings);
            Assert.IsNotNull(databaseConnectionInfo);
            //---------------Execute Test ----------------------
            ReverseEngineering reverseEngineeringForSolution = controller.CreateReverseEngineeringForSolution(reverseEngineeringSettings, databaseConnectionInfo);
            //---------------Test Result -----------------------
            Assert.IsNotNull(reverseEngineeringForSolution);
            Assert.AreSame(controller.Solution.ReverseEngineering, reverseEngineeringForSolution);
        }

        [Test]
        public void Test_CreateReverseEngineeringForSolution_WhenCalledWithValidParametersAndSolutionHasAssociatedReverseEngineering_ShouldReturnReverseEngineeringAlreadyAssociatedWithTheSolution()
        {
            //---------------Set up test pack-------------------
            DBToDMReverseEngineeringController controller = CreateDBToDMReverseEngineeringControllerWithEmptySolution();
            ReverseEngineeringSettings reverseEngineeringSettings = new ReverseEngineeringSettings();
            DatabaseConnectionInfo databaseConnectionInfo = new DatabaseConnectionInfo();
            ReverseEngineering reverseEngineering =
                TestUtilsReverseEngineering.CreateUnsavedValidReverseEngineering();
            ReverseEngineering emptyReverseEngineering = new ReverseEngineering();
            var solution = controller.Solution;
            solution.ReverseEngineering = reverseEngineering;
            //---------------Assert Precondition----------------
            // This first Assert is just to ensure we are not only testing against a new'ed up instance of ReverseEngineering 
            // as this is what is returned if no reverse engineering is set on the solution
            Assert.AreNotSame(emptyReverseEngineering, reverseEngineering);
            Assert.IsNotNull(reverseEngineeringSettings);
            Assert.IsNotNull(databaseConnectionInfo);
            Assert.IsNotNull(solution);
            Assert.AreSame(solution, controller.Solution);
            Assert.AreSame(reverseEngineering, controller.Solution.ReverseEngineering);
            //---------------Execute Test ----------------------
            ReverseEngineering reverseEngineeringForSolution = controller.CreateReverseEngineeringForSolution(reverseEngineeringSettings, databaseConnectionInfo);
            //---------------Test Result -----------------------
            Assert.AreSame(solution, controller.Solution);
            Assert.AreSame(reverseEngineering,reverseEngineeringForSolution);
            Assert.AreSame(reverseEngineering, controller.Solution.ReverseEngineering);
        }


        private static DBToDMReverseEngineeringController CreateDBToDMReverseEngineeringControllerWithEmptySolution()
        {
            var solution = new SolutionCreator().CreateSolution();
            return new DBToDMReverseEngineeringController(solution);
        }

        // ReSharper restore InconsistentNaming


        internal class ReverseEngineeringFake : ReverseEngineering
        {}
    }

  



    internal class DBToDMReverseEngineeringControllerSpy : DBToDMReverseEngineeringController
    {
        public DBToDMReverseEngineeringControllerSpy(DMSolution solution) : base(solution)
        {
        }

        public IPropertyTypeStorer PropertyTypeStorerGetter()
        {
            return base.PropertyTypeStorer;
        }
    }

}
